/* eslint-disable no-prototype-builtins */
/* eslint-disable no-cond-assign */
/* eslint-disable no-use-before-define */
/* eslint-disable no-useless-escape */
import { T_srv, Tsrv, ifs, ts, vue } from '@/services';

const cmConf = {
  mode: 'application/json',
  theme: 'base16-light', // 主题样式
  lint: true,
  tabSize: 2,
  smartIndent: true, // 是否智能缩进
  styleActiveLine: true, // 当前行高亮
  lineNumbers: true, // 显示行号
  gutters: [
    'CodeMirror-linenumbers',
    'CodeMirror-foldgutter',
    'CodeMirror-lint-markers'
  ],
  lineWrapping: true, // 自动换行
  matchBrackets: true, // 括号匹配显示
  autoCloseBrackets: true, // 输入和退格时成对
  readOnly: false, // 只读
  foldGutter: true
};
const regMode = (CodeMirror, t) => {
  if (CodeMirror.getMode({}, `wyrule`).name !== 'null') {
    return;
  }

  CodeMirror.defineMode('wyrule', function(config) {
    const ALIGN_YES = 1;
    const ALIGN_NO = 2;
    const BRACELESS = 4;

    // 关键字
    const keywords = {
      if: true,
      then: true,
      and: true,
      or: true,
      match: true,
      noMatch: true,
      not: true,
      between: true,
      switch: true,
      case: true,
      declare: true,
      string: true,
      number: true,
      boolean: true,
      other: true,
      return: true
    };

    // 符号
    const isOperatorChar = /[+\-*&^%:=<>!|\/]/;

    const tokenComment = (stream, state) => {
      let maybeEnd = false;
      let ch;

      while ((ch = stream.next())) {
        if (ch === '/' && maybeEnd) {
          state.tokenize = tokenBase;
          break;
        }
        maybeEnd = ch === '*';
      }
      return 'comment';
    };

    // 参考D:\vue\wyJs\node_modules\codemirror\mode\go\go.js
    const tokenBase = (stream, state) => {
      const ch = stream.next();
      // 字符串
      if (ch === '"') {
        state.tokenize = tokenString(ch);
        return 'string';
      }
      // 数字
      if (/[\d\.]/.test(ch)) {
        if (ch === '.') {
          stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/);
        } else if (ch === '0') {
          stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/);
        } else {
          stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/);
        }
        return 'number';
      }
      if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
        return null;
      }

      if (ch === '/') {
        if (stream.eat('*')) {
          state.tokenize = tokenComment;
          return tokenComment(stream, state);
        }
        if (stream.eat('/')) {
          stream.skipToEnd();
          return 'comment';
        }
      }

      if (isOperatorChar.test(ch)) {
        stream.eatWhile(isOperatorChar);
        return 'operator';
      }
      // 标识符改为不带[]
      // // 属性
      // if (ch === '[') {
      //   // // 如果是函数带参数 [a.b.c()]
      //   // const str = stream.string.substring(stream.pos);
      //   // if (
      //   //   /.\(.*\)/.test(
      //   //     stream.string.substring(stream.pos, str.indexOf(']') + stream.pos)
      //   //   )
      //   // ) {
      //   //   state.tokenize = tokenAttr('(');
      //   // } else {
      //   //   state.tokenize = tokenAttr(']');
      //   // }
      //   state.tokenize = tokenAttr(']');
      //   return 'string-2';
      // }
      // if (ch === ']') {
      //   return 'string-2';
      // }

      // // a.b.c
      // if (ch === '.' && stream.match(/.(?:[.]|\d+)/)) {
      //   return 'keyword';
      // }
      if (/\w/.test(ch)) {
        state.tokenize = tokenI18nAndKeyWorkHandle();
        return state.tokenize(stream, state);
      }
      return null;
    };
    const tokenString = quote => {
      return function(stream, state) {
        let next;

        while ((next = stream.next()) != null) {
          if (next === quote) {
            state.tokenize = tokenBase;
            break;
          }
        }
        return 'string';
      };
    };

    const tokenAttr = quote => {
      return (stream, state) => {
        let next;

        while ((next = stream.next()) != null) {
          if (next === quote) {
            state.tokenize = tokenBase;
            state.currLine = stream.lineOracle.line;
            stream.backUp(1);
            state.i18nKeyValue = stream.string.substring(
              stream.start,
              stream.pos
            );
            state.i18nValue = t(state.i18nKeyValue);
            // 如果i18n不能全布转换则返回空
            if (state.i18nValue !== '') {
              state.isI18n = true;
            }
            break;
          }
        }
        return 'attribute';
      };
    };

    const tokenI18nAndKeyWorkHandle = () => {
      return (stream, state) => {
        let i18nV: string;
        let str: string;
        let next: string;

        state.tokenize = tokenBase; // 更换执行指针到外部函数
        stream.backUp(1);

        while ((next = stream.next()) != null) {
          // 非字符
          if (/\W/.test(next)) {
            stream.backUp(1);
            return null;
          }
          // 返回当前 token 开始位置到当前 stream 位置之间的字符串。
          const cur = stream.current();
          i18nV = t(cur);

          if (i18nV && !state.isI18n) {
            state.currLine = stream.lineOracle.line;
            state.i18nKeyValue = str;
            state.i18nValue = i18nV;
            state.isI18n = true;
            return 'attribute';
          }
          if (keywords.propertyIsEnumerable(cur)) {
            return 'keyword';
          }
        }

        return null;
      };
    };

    const push = (state, type, stream) => {
      state.ctx = {
        type,
        indent: state.indent,
        flags: 0,
        column: stream.column(),
        prev: state.ctx
      };
    };
    const setFlag = (state, flag) => {
      const ctx = state.ctx;
      state.ctx = {
        type: ctx.type,
        indent: ctx.indent,
        flags: ctx.flags | flag,
        column: ctx.column,
        prev: ctx.prev
      };
    };
    const pop = state => {
      state.indent = state.ctx.indent;
      state.ctx = state.ctx.prev;
    };

    return {
      startState() {
        return {
          tokenize: null,
          ctx: { type: 'top', indent: -config.indentUnit, flags: ALIGN_NO },
          // 缩进
          indent: 0,
          // 识别后
          afterIdent: false,
          isI18n: false,
          i18nValue: '',
          i18nKeyValue: '',
          currLine: null
        };
      },
      // stream 对象封装了一行的源码 state = startState()
      token(stream, state) {
        state.isI18n = false;
        state.i18nValue = '';
        // 是否在行首
        if (stream.sol()) {
          if ((state.ctx.flags & 3) === 0) state.ctx.flags |= ALIGN_NO;
          if (state.ctx.flags & BRACELESS) pop(state);
          state.indent = stream.indentation();
        }
        // eatSpace() → boolean 用 eatWhile 匹配空格的快捷函数。
        if (stream.eatSpace()) return null;
        const style = (state.tokenize || tokenBase)(stream, state);
        if (style !== 'comment' && (state.ctx.flags & ALIGN_NO) === 0) {
          setFlag(state, ALIGN_YES);
        }
        state.afterIdent = style === 'variable' || style === 'keyword';
        return style;
      },

      indent(state, textAfter) {
        if (state.tokenize !== tokenBase) return 0;
        const firstChar = textAfter && textAfter.charAt(0);
        let ctx = state.ctx;
        const closing = firstChar === ctx.type;
        if (ctx.flags & BRACELESS) ctx = ctx.prev;
        if (ctx.type === 'block')
          return ctx.indent + (firstChar === '{' ? 0 : config.indentUnit);
        if (ctx.flags & ALIGN_YES) return ctx.column + (closing ? 0 : 1);
        return ctx.indent + (closing ? 0 : config.indentUnit);
      },

      lineComment: '//'
    };
  });
};

export { T_srv, Tsrv, cmConf, ifs, regMode, ts, vue };
